package fussbudget.gui;

import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.swing.AbstractCellEditor;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.border.TitledBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

import org.joda.money.Money;
import org.joda.time.DateMidnight;

import com.lavantech.gui.comp.DateTimePicker;

import fussbudget.FussBudgetMain;
import fussbudget.PaymentEntity;
import fussbudget.ScheduledTransaction;
import fussbudget.ScheduledTransaction.RECURRANCE;
import fussbudget.Transaction;
import fussbudget.SQL.FBSQL;
import fussbudget.SQL.SQLUtility;
import fussbudget.abstracts.AbstractTableWithPopup;
import fussbudget.gui.TransactionTablePanel.DateCellEditor;
import fussbudget.gui.TransactionTablePanel.PaymentEntityEditor;
import fussbudget.gui.components.BasicPopupMenu;
import fussbudget.gui.components.HasPopupMenu;

public class ScheduleTablePanel extends JScrollPane implements HasPopupMenu {
	public Container				parent;
	public AbstractTableWithPopup	table;
	public ScheduleModel			model;
	public BasicPopupMenu			popup;

	public ScheduleTablePanel(String name, Container parent, Transaction.TYPE type) {
		super();

		this.parent = parent;

		setBorder(new TitledBorder(name));

		model = new ScheduleModel();
		model.type = type;
		populateModel();

		table = new AbstractTableWithPopup(5, 3);
		table.setFillsViewportHeight(true);
		table.setModel(model);
		table.setDefaultRenderer(Object.class, new ScheduleTableRenderer());
		table.setDefaultEditor(DateMidnight.class, new DateCellEditor());
		table.setDefaultEditor(PaymentEntity.class, new PaymentEntityEditor());

		initColumnSizes(table);

		this.getViewport().setView(table);

		setupPopup();
	}

	public BasicPopupMenu getPopup() {
		return popup;
	}

	public void setPopup(BasicPopupMenu newPopup) {
		this.popup = newPopup;
	}

	public void populateModel() {
		ResultSet rs = null;
		switch (model.type) {
			case DEPOSIT:
				rs = FBSQL.getResultSetFromActiveDB("scheduledTransaction", "*", "isDeposit=" + true);
				break;
			case PAYMENT:
				rs = FBSQL.getResultSetFromActiveDB("scheduledTransaction", "*", "isDeposit=" + false);
				break;
		}
		
		SQLUtility.lock();
		if (rs != null) {
			try {
				while (rs.next()) {
					ScheduledTransaction transaction = new ScheduledTransaction(rs);
					model.addRow(transaction);
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		SQLUtility.unlock();
	}

	@Override
	public void setupPopup() {
		ArrayList<HasPopupMenu> haveMenu = new ArrayList<HasPopupMenu>();
		haveMenu.add(this);
		haveMenu.add(table);
		// haveMenu.add((TableHeaderWithPopup)table.getTableHeader());

		popup = new BasicPopupMenu(haveMenu);
		popup.addMenuItem("Add", new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				System.out.println("Add new Scheduled Transaction...");
				ScheduledTransaction newTransaction = new ScheduledTransaction("NEW SCHEDULED TRANSACTION");
				newTransaction.setType(model.type);
				model.addRow(newTransaction);
			}
		});
		popup.addMenuItem("Delete", new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				System.out.println("Delete Scheduled Transaction...");
				int whichRow = table.getSelectedRow();
				((ScheduleModel) table.getModel()).removeRow(whichRow);
				table.revalidate();
				table.repaint();
			}
		});
	}

	private void initColumnSizes(JTable table) {
		ScheduleModel model = (ScheduleModel) table.getModel();
		TableColumn column = null;
		Component comp = null;
		int headerWidth = 0;
		int cellWidth = 0;

		TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();

		for (int i = 0; i < model.getColumnCount(); i++) {
			column = table.getColumnModel().getColumn(i);

			comp = headerRenderer.getTableCellRendererComponent(null, column.getHeaderValue(), false, false, 0, 0);
			headerWidth = comp.getPreferredSize().width;

			// comp = table.getDefaultRenderer(model.getColumnClass(i)).getTableCellRendererComponent(table, longValues[i], false, false, 0, i);
			// cellWidth = comp.getPreferredSize().width;

			column.setPreferredWidth(headerWidth);
		}
	}

	public class ScheduleModel extends AbstractTableModel {
		private String[]						columnNames	= { "NAME", "START DATE", "AMOUNT", "RECURRANCE", "WHO..." };
		private ArrayList<ScheduledTransaction>	data		= new ArrayList<ScheduledTransaction>();
		public Transaction.TYPE					type;

		public void addRow(ScheduledTransaction newTransaction) {
			data.add(newTransaction);
			int newRow = data.size() - 1;
			this.fireTableRowsInserted(newRow, newRow);
		}

		public void removeRow(int row) {
			data.remove(row);
		}

		public String getColumnName(int col) {
			return columnNames[col];
		}

		@Override
		public int getColumnCount() {
			return columnNames.length;
		}

		@Override
		public int getRowCount() {
			return data.size();
		}

		@Override
		public Object getValueAt(int row, int col) {
			ScheduledTransaction currRow = data.get(row);
			switch (col) {
				case 0:
					return currRow.getName();
				case 1:
					return currRow.getStartTransaction().getDate();
				case 2:
					return currRow.getStartTransaction().getAmount();
				case 3:
					return currRow.getRecurrance();
				case 4:
					return currRow.getPaymentEntity();
			}
			return "";
		}

		public Class getColumnClass(int c) {
			Object v = getValueAt(0, c);
			return v.getClass();
		}

		public void setValueAt(Object value, int row, int col) {
			ScheduledTransaction currRow = data.get(row);
			switch (col) {
				case 0:
					currRow.setName((String) value);
					break;
				case 1:
					currRow.getStartTransaction().setDate((DateMidnight) value);
					break;
				case 2:
					currRow.getStartTransaction().setAmount((Money) value);
					break;
				case 3:
					currRow.setRecurrance((String) value);
					break;
				case 4:
					currRow.setPaymentEntity((PaymentEntity) value);
					break;
			}
			fireTableCellUpdated(row, col);
		}

		public boolean isCellEditable(int row, int col) {
			return true;
		}

	}

	public class ScheduleTableRenderer extends DefaultTableCellRenderer {
		public ScheduleTableRenderer() {
			super();
		}

		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
			if (value instanceof String) {
				return new JLabel((String) value);
			} else if (value instanceof DateMidnight) {
				return new DateTimePicker(((DateMidnight) value).toDate(), "MM/dd/yyyy", true, false);
			} else if (value instanceof Money) {
				JLabel label = new JLabel(((Money) value).toString());
				label.setHorizontalAlignment(SwingConstants.CENTER);
				return label;
			} else if (value instanceof PaymentEntity) {
				JLabel label = new JLabel(((PaymentEntity) value).getName());
				label.setHorizontalAlignment(SwingConstants.CENTER);
				return label;
			} else if (value instanceof RECURRANCE){
				JLabel label = new JLabel(((RECURRANCE)value).name());
				label.setHorizontalAlignment(SwingConstants.CENTER);
				return label;
			}
			return new JLabel((String) value);
		}
	}

	public class PaymentEntityEditor extends AbstractCellEditor implements TableCellEditor {
		PaymentEntityComboBox	picker	= null;

		@Override
		public Object getCellEditorValue() {
			return picker.getSelectedItem();
		}

		@Override
		public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
			switch (model.type) {
				case DEPOSIT:
					picker = new PaymentEntityComboBox(FussBudgetMain.payerSet.toComboBoxModel((PaymentEntity) value));
					break;
				case PAYMENT:
					picker = new PaymentEntityComboBox(FussBudgetMain.payeeSet.toComboBoxModel((PaymentEntity) value));
					break;
			}
			return picker;
		}

	}

	public class DateCellEditor extends AbstractCellEditor implements TableCellEditor {
		DateTimePicker	picker	= new DateTimePicker();

		@Override
		public Object getCellEditorValue() {
			return new DateMidnight(picker.getDate());
		}

		@Override
		public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
			picker = new DateTimePicker(((DateMidnight) value).toDate(), "MM/dd/yyyy", true, false);
			return picker;
		}

	}

}
